From 9a01a03d51ddc5438a7e88b3b701d081b4fd23a1 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Thu, 28 Sep 2006 17:09:11 +0100 Subject: [PATCH] [XEN] Fix interaction between tlbflush timestamp and shadow flags Signed-off-by: Tim Deegan --- xen/arch/x86/mm.c | 17 +++++++++++------ xen/arch/x86/mm/shadow/common.c | 4 ++++ xen/include/asm-x86/shadow.h | 5 +++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 8b09e26f8f..d7041c7af1 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -1544,9 +1544,7 @@ void free_page_type(struct page_info *page, unsigned long type) gmfn = mfn_to_gmfn(owner, page_to_mfn(page)); ASSERT(VALID_M2P(gmfn)); - shadow_lock(owner); shadow_remove_all_shadows(owner->vcpu[0], _mfn(gmfn)); - shadow_unlock(owner); } } @@ -1618,8 +1616,8 @@ void put_page_type(struct page_info *page) * 2. Shadow mode reuses this field for shadowed page tables to * store flags info -- we don't want to conflict with that. */ - if ( !shadow_mode_enabled(page_get_owner(page)) || - ((nx & PGT_type_mask) == PGT_writable_page) ) + if ( !(shadow_mode_enabled(page_get_owner(page)) && + (page->count_info & PGC_page_table)) ) page->tlbflush_timestamp = tlbflush_current_time(); } } @@ -1644,6 +1642,12 @@ int get_page_type(struct page_info *page, unsigned long type) } else if ( unlikely((x & PGT_count_mask) == 0) ) { + struct domain *d = page_get_owner(page); + + /* Never allow a shadowed frame to go from type count 0 to 1 */ + if ( d && shadow_mode_enabled(d) ) + shadow_remove_all_shadows(d->vcpu[0], _mfn(page_to_mfn(page))); + ASSERT(!(x & PGT_pae_xen_l2)); if ( (x & PGT_type_mask) != type ) { @@ -1652,8 +1656,9 @@ int get_page_type(struct page_info *page, unsigned long type) * may be unnecessary (e.g., page was GDT/LDT) but those * circumstances should be very rare. */ - cpumask_t mask = - page_get_owner(page)->domain_dirty_cpumask; + cpumask_t mask = d->domain_dirty_cpumask; + + /* Don't flush if the timestamp is old enough */ tlbflush_filter(mask, page->tlbflush_timestamp); if ( unlikely(!cpus_empty(mask)) && diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index fa530c06ca..f2fafe1176 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -256,7 +256,11 @@ void shadow_demote(struct vcpu *v, mfn_t gmfn, u32 type) clear_bit(type >> PGC_SH_type_shift, &page->shadow_flags); if ( (page->shadow_flags & SHF_page_type_mask) == 0 ) + { + /* tlbflush timestamp field is valid again */ + page->tlbflush_timestamp = tlbflush_current_time(); clear_bit(_PGC_page_table, &page->count_info); + } } /**************************************************************************/ diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index 94a4ff11fd..d6c9688de7 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -481,7 +481,12 @@ shadow_remove_all_shadows_and_parents(struct vcpu *v, mfn_t gmfn); extern void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int all); static inline void shadow_remove_all_shadows(struct vcpu *v, mfn_t gmfn) { + int was_locked = shadow_lock_is_acquired(v->domain); + if ( !was_locked ) + shadow_lock(v->domain); sh_remove_shadows(v, gmfn, 1); + if ( !was_locked ) + shadow_unlock(v->domain); } /* Add a page to a domain */ -- 2.30.2